﻿using CleanArchitecture.Core.Handlers;
using CleanArchitecture.Infrastructure.Entities.Settings;
using CleanArchitecture.Infrastructure.Interfaces.Authentication;
using CleanArchitecture.Infrastructure.Services.Authentication;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Text;
using System.Threading.Tasks;

namespace CleanArchitecture.Infrastructure.Plugins.JwtAuthenticationRegistrar
{
    /// <summary>
    /// Represents registrar of Jwt authentication service
    /// </summary>
    public class JwtAuthenticationRegistrar : IExternalAuthenticationRegistrar
    {
        /// <summary>
        /// Configure
        /// https://www.cnblogs.com/danvic712/p/10331976.html
        /// </summary>
        /// <param name="builder">Authentication builder</param>
        public void Configure(AuthenticationBuilder builder)
        {
            builder.AddJwtBearer(AuthenticationDefaultConfig.JwtAuthenticationScheme, options =>
            {
                //set credentials
                var settings = EngineContext.Current.Resolve<SecuritySettings>();
                TimeSpan expiration = settings.JwtExpirationMinutes <= 0
                                    ? TimeSpan.FromMinutes(Convert.ToDouble(AuthenticationDefaultConfig.JwtExpirationMinutes))
                                    : TimeSpan.FromMinutes(Convert.ToDouble(settings.JwtExpirationMinutes));
                var SecurityKey = string.IsNullOrEmpty(settings.JwtIssuerSigningKey)
                                ? new SymmetricSecurityKey(Encoding.UTF8.GetBytes(AuthenticationDefaultConfig.JwtIssuerSigningKey))
                                : new SymmetricSecurityKey(Encoding.UTF8.GetBytes(settings.JwtIssuerSigningKey));
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,           //是否验证Issuer
                    ValidateAudience = true,         //是否验证Audience
                    ValidateLifetime = true,         //是否验证失效时间
                    ValidateIssuerSigningKey = true, //是否验证SecurityKey
                    ClockSkew = expiration,
                    ValidAudience = string.IsNullOrEmpty(settings.JwtValidAudience) //Audience
                                  ? AuthenticationDefaultConfig.JwtValidAudience
                                  : settings.JwtValidAudience,
                    ValidIssuer = string.IsNullOrEmpty(settings.JwtValidIssuer)     //Issuer，这两项和前面签发jwt的设置一致
                                ? AuthenticationDefaultConfig.JwtValidIssuer
                                : settings.JwtValidIssuer,
                    IssuerSigningKey = SecurityKey                                  //拿到SecurityKey
                };
                options.Events = new JwtBearerEvents
                {
                     OnAuthenticationFailed = context =>
                     {
                         //Token expired
                         if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                         {
                             context.Response.Headers.Add("Token-Expired", "true");
                         }
                         return Task.CompletedTask;
                     }
                 };
            });
        }
    }
}
